package com.example.qxfw.shfx.Service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.dmgis.entity.*;
import com.dmgis.weblib.MapCommon;
import com.example.qxfw.common.entity.CountyPoint;
import com.example.qxfw.common.entity.qx.AreaRain;
import com.example.qxfw.common.entity.qx.MsgMediumSmallScale;
import com.example.qxfw.common.entity.qx.TownshipForecast;
import com.example.qxfw.common.entity.zy.RainWaterShed;
import com.example.qxfw.common.util.DateUtil;
import com.example.qxfw.common.util.DmgisUtils;
import com.example.qxfw.shfx.Mapper.AreaRainMapper;
import com.example.qxfw.shfx.Mapper.CountyPointMapper;
import com.example.qxfw.shfx.Mapper.RainWaterShedMapper;
import com.example.qxfw.shfx.Service.MylfxService;
import com.example.qxfw.shfx.dto.Mylfx;
import com.example.qxfw.ybzz.mapper.MsgMediumSmallScaleMapper;
import com.example.qxfw.ybzz.mapper.TownshipForecastMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.sql.Timestamp;
import java.util.*;


@Slf4j
@Service
public class MylfxServiceImpl implements MylfxService {
    @Autowired
    private AreaRainMapper areaRainMapper;
    @Autowired
    private MsgMediumSmallScaleMapper msgMediumSmallScaleMapper;
    @Autowired
    private TownshipForecastMapper townshipForecastMapper;
    @Autowired
    private RainWaterShedMapper rainWaterShedMapper;
    @Autowired
    private CountyPointMapper countyPointMapper;

    @Override
    public List<Mylfx> RealTimeSurfaceRainfall(String startDate, String endDate, String startTime, String endTime, Short areaType) {
        // 获取区域雨量统计表数据
        List<AreaRain> areaRains;
        List<Mylfx> list = new ArrayList<>();
        // 处理时间是时点还是时段
        Timestamp start = DateUtil.localDateTimeToTimestamp(DateUtil.stringToLocalDateTime(startDate + " " + startTime + ":00:00"));
        Timestamp end = null;
        if (StringUtils.isNotBlank(endDate) && !endDate.equals("null") && endTime != null && !endTime.isEmpty()) {
            end = DateUtil.localDateTimeToTimestamp(DateUtil.stringToLocalDateTime(endDate + " " + endTime + ":00:00"));
        }
        int type = 0;
        if (end == null) {
            areaRains = areaRainMapper.selectList(new LambdaQueryWrapper<AreaRain>()
                    .eq(AreaRain::getObservtime, start)
                    .eq(AreaRain::getType, type)
                    .eq(AreaRain::getAreatype, areaType));
        } else {
            areaRains = areaRainMapper.selectList(new LambdaQueryWrapper<AreaRain>()
                    .between(AreaRain::getObservtime, start, end)
                    .eq(AreaRain::getType, type)
                    .eq(AreaRain::getAreatype, areaType));
        }
        if (areaRains.size() > 0) {
            for (AreaRain areaRain : areaRains) {
                // 判断为流域还是行政区(0流域，1行政)
                if (areaRain.getAreatype() == 0) {
                    // 根据流域名获取经纬度
                    RainWaterShed rainWaterShed = rainWaterShedMapper.selectOne(new LambdaQueryWrapper<RainWaterShed>()
                            .select(RainWaterShed::getName, RainWaterShed::getCenterpointx, RainWaterShed::getCenterpointy)
                            .eq(RainWaterShed::getName, areaRain.getAreaname()));
                    if (rainWaterShed != null) {
                        list.add(new Mylfx(rainWaterShed.getName(), areaRain.getRain(), rainWaterShed.getCenterpointx(), rainWaterShed.getCenterpointy()));
                    } else {
                        log.warn("表RainWaterShed中没有查询到表AreaRain对应的信息！");
                    }
                } else {
                    CountyPoint countyPoint = countyPointMapper.selectOne(new LambdaQueryWrapper<CountyPoint>()
                            .select(CountyPoint::getName, CountyPoint::getLon, CountyPoint::getLat)
                            .eq(CountyPoint::getName, areaRain.getAreaname()));
                    if (countyPoint != null) {
                        list.add(new Mylfx(countyPoint.getName(), areaRain.getRain(), countyPoint.getLon(), countyPoint.getLat()));
                    } else {
                        log.warn("表CountyPoint中没有查询到表AreaRain对应的信息！");
                    }
                }
            }
            return list;
        }
        log.warn("区域雨量统计表无符合条件的数据！！！");
        log.warn("生成数据中...");

        List<MsgMediumSmallScale> msgList = new ArrayList<>();
        // 按照时间点生成数据
        if (end == null) {
            msgList = msgMediumSmallScaleMapper.selectList(new LambdaQueryWrapper<MsgMediumSmallScale>()
                    .select(MsgMediumSmallScale::getLongitude, MsgMediumSmallScale::getLatitude, MsgMediumSmallScale::getRain)
                    .eq(MsgMediumSmallScale::getObservtime, start));

            if (msgList.size() > 0) {
                // 判断查询流域还是行政区
                if (areaType == 0) {
                    // 获取玉林市的所有流域
                    List<RainWaterShed> rainWaterSheds = rainWaterShedMapper.selectList(new LambdaQueryWrapper<RainWaterShed>()
                            .eq(RainWaterShed::getDrainagearea, "玉林"));
                    // 处理流域的点集（每组坐标用“；”隔开  一组坐标以“，”隔开）
                    for (RainWaterShed waterShed : rainWaterSheds) {
                        // 流域的面的点集
                        List<DmMapPoint> points = new ArrayList<>();
                        String[] split = waterShed.getCoordinate().split(";");
                        for (int i = 0; i < split.length; i++) {
                            String[] split1 = split[i].split(",");
                            points.add(new DmMapPoint(Double.parseDouble(split1[0]), Double.parseDouble(split1[1])));
                        }

                        // 判断点在面内并准备好()方法所需要的参数
                        List<Float> floatList = new ArrayList<>();
                        List<Point3D> point3Ds = new ArrayList<>();
                        for (MsgMediumSmallScale smallScale : msgList) {
                            boolean b = MapCommon.pointWithinPolygon(points, smallScale.getLongitude(), smallScale.getLatitude());
                            if (b) {
                                floatList.add(smallScale.getRain());
                                point3Ds.add(new Point3D(smallScale.getLongitude(), smallScale.getLatitude(), smallScale.getRain()));
                            }
                        }
                        // 将集合转化为数组
                        Float[] fvals = floatList.toArray(new Float[floatList.size()]);

                        float[] fs = new float[fvals.length];
                        for (int i = 0; i < fvals.length; i++) {
                            fs[i] = fvals[i];
                        }

                        // 三角网插值，需要至少三个点
                        if (fvals.length > 3) {
                            // 计算最大最小值
                            Float max = Arrays.stream(fvals).max(Float::compareTo).orElse(null);
                            Float min = Arrays.stream(fvals).min(Float::compareTo).orElse(null);
                            // 将在面内的点的计入面雨量求值
                            double areaRain = DmgisUtils.getAreaRainWgs(min, max, fs, points, point3Ds);
                            // 计算完毕返回对象
                            list.add(new Mylfx(waterShed.getName(), areaRain, waterShed.getCenterpointx(), waterShed.getCenterpointy()));
                        } else {
                            log.warn("三角网插值，需要至少三个点。当前流域为：" + waterShed.getName() + "，符合条件的值有：" + fvals.length + "个");
                        }
                    }
                    return list;
                    // 处理为行政区的情况
                } else {
                    // 获取玉林市的所有行政区:在表county_point里有行政区的信息，目前这里的所有数据都是玉林的，如果后期有其他区域的可以添加一个过滤条件
                    List<CountyPoint> countyPoints = countyPointMapper.selectList(new LambdaQueryWrapper<CountyPoint>()
                            .select(CountyPoint::getName, CountyPoint::getLon, CountyPoint::getLat, CountyPoint::getRange));

                    // 处理行政区的点集（每组坐标用“；”隔开  一组坐标以“，”隔开）
                    for (CountyPoint countyPoint : countyPoints) {
                        // 行政区的面的点集
                        List<DmMapPoint> points = new ArrayList<>();
                        String[] split = countyPoint.getRange().split(";");
                        for (int i = 0; i < split.length; i++) {
                            String[] split1 = split[i].split(",");
                            points.add(new DmMapPoint(Double.parseDouble(split1[0]), Double.parseDouble(split1[1])));
                        }
                        // 判断点在面内并准备好getAreaRain()方法所需要的参数
                        List<Float> floatList = new ArrayList<>();
                        List<Point3D> point3Ds = new ArrayList<>();
                        for (MsgMediumSmallScale smallScale : msgList) {
                            boolean b = MapCommon.pointWithinPolygon(points, smallScale.getLongitude(), smallScale.getLatitude());
                            if (b) {
                                floatList.add(smallScale.getRain());
                                point3Ds.add(new Point3D(smallScale.getLongitude(), smallScale.getLatitude(), smallScale.getRain()));
                            }
                        }
                        // 将集合转化为数组
                        Float[] fvals = floatList.toArray(new Float[floatList.size()]);

                        float[] fs = new float[fvals.length];
                        for (int i = 0; i < fvals.length; i++) {
                            fs[i] = fvals[i];
                        }

                        // 三角网插值，需要至少三个点
                        if (fvals.length > 3) {
                            // 计算最大最小值
                            Float max = Arrays.stream(fvals).max(Float::compareTo).orElse(null);
                            Float min = Arrays.stream(fvals).min(Float::compareTo).orElse(null);
                            // 将在面内的点的计入面雨量求值
//                            double areaRain = DmgisUtils.getAreaRain(min, max, fs, points, point3Ds);
                            double areaRain = DmgisUtils.getAreaRainWgs(min, max, fs, points, point3Ds);
                            // 计算完毕返回对象
                            list.add(new Mylfx(countyPoint.getName(), areaRain, countyPoint.getLon(), countyPoint.getLat()));
                        } else {
                            log.warn("三角网插值，需要至少三个点。当前行政面为：" + countyPoint.getName() + "，符合条件的值有：" + fvals.length + "个");
                        }
                    }
                    return list;
                }
            }
        } else {
            msgList = msgMediumSmallScaleMapper.selectList(new LambdaQueryWrapper<MsgMediumSmallScale>()
                    .select(MsgMediumSmallScale::getLongitude, MsgMediumSmallScale::getLatitude, MsgMediumSmallScale::getRain)
                    .between(MsgMediumSmallScale::getObservtime, start, end));
            if (msgList.size() > 0) {
                // 判断查询流域还是行政区
                if (areaType == 0) {
                    // 获取玉林市的所有流域
                    List<RainWaterShed> rainWaterSheds = rainWaterShedMapper.selectList(new LambdaQueryWrapper<RainWaterShed>()
                            .like(RainWaterShed::getDrainagearea, "玉林"));
                    // 处理流域的点集（每组坐标用“；”隔开  一组坐标以“，”隔开）
                    for (RainWaterShed waterShed : rainWaterSheds) {
                        // 流域的面的点集
                        List<DmMapPoint> points = new ArrayList<>();
                        String[] split = waterShed.getCoordinate().split(";");
                        for (int i = 0; i < split.length; i++) {
                            String[] split1 = split[i].split(",");
                            points.add(new DmMapPoint(Double.valueOf(split1[0]), Double.valueOf(split1[1])));
                        }
                        // 判断点在面内并准备好getAreaRain()方法所需要的参数
                        List<Float> floatList = new ArrayList<>();
                        List<Point3D> point3Ds = new ArrayList<>();
                        for (MsgMediumSmallScale smallScale : msgList) {
                            boolean b = MapCommon.pointWithinPolygon(points, smallScale.getLongitude(), smallScale.getLatitude());
                            if (b) {
                                floatList.add(smallScale.getRain());
                                point3Ds.add(new Point3D(smallScale.getLongitude(), smallScale.getLatitude(), smallScale.getRain()));
                            }
                        }
                        // 将集合转化为数组
                        Float[] fvals = floatList.toArray(new Float[floatList.size()]);

                        float[] fs = new float[fvals.length];
                        for (int i = 0; i < fvals.length; i++) {
                            fs[i] = fvals[i];
                        }
                        // 三角网插值，需要至少三个点
                        if (fvals.length > 3) {
                            // 计算最大最小值
                            Float max = Arrays.stream(fvals).max(Float::compareTo).orElse(null);
                            Float min = Arrays.stream(fvals).min(Float::compareTo).orElse(null);
                            // 将在面内的点的计入面雨量求值
                            double areaRain = DmgisUtils.getAreaRainWgs(min, max, fs, points, point3Ds);
                            // 计算完毕返回对象
                            list.add(new Mylfx(waterShed.getName(), areaRain, waterShed.getCenterpointx(), waterShed.getCenterpointy()));
                        } else {
                            log.warn("三角网插值，需要至少三个点。当前流域为：" + waterShed.getName() + "，符合条件的值有：" + fvals.length + "个");
                        }
                    }
                    return list;
                    // 处理为行政区的情况
                } else {
                    // 获取玉林市的所有行政区:在表county_point里有行政区的信息，目前这里的所有数据都是玉林的，如果后期有其他区域的可以添加一个过滤条件
                    List<CountyPoint> countyPoints = countyPointMapper.selectList(new LambdaQueryWrapper<CountyPoint>()
                            .select(CountyPoint::getName, CountyPoint::getLon, CountyPoint::getLat, CountyPoint::getRange));

                    // 处理行政区的点集（每组坐标用“；”隔开  一组坐标以“，”隔开）
                    for (CountyPoint countyPoint : countyPoints) {
                        // 行政区的面的点集
                        List<DmMapPoint> points = new ArrayList<>();
                        String[] split = countyPoint.getRange().split(";");
                        for (int i = 0; i < split.length; i++) {
                            String[] split1 = split[i].split(",");
                            points.add(new DmMapPoint(Double.parseDouble(split1[0]), Double.parseDouble(split1[1])));
                        }
                        // 判断点在面内并准备好getAreaRain()方法所需要的参数
                        List<Float> floatList = new ArrayList<>();
                        List<Point3D> point3Ds = new ArrayList<>();
                        for (MsgMediumSmallScale smallScale : msgList) {
                            boolean b = MapCommon.pointWithinPolygon(points, smallScale.getLongitude(), smallScale.getLatitude());
                            if (b) {
                                floatList.add(smallScale.getRain());
                                point3Ds.add(new Point3D(smallScale.getLongitude(), smallScale.getLatitude(), smallScale.getRain()));
                            }
                        }
                        // 将集合转化为数组
                        Float[] fvals = floatList.toArray(new Float[floatList.size()]);

                        float[] fs = new float[fvals.length];
                        for (int i = 0; i < fvals.length; i++) {
                            fs[i] = fvals[i];
                        }

                        // 三角网插值，需要至少三个点
                        if (fvals.length > 3) {
                            // 计算最大最小值
                            Float max = Arrays.stream(fvals).max(Float::compareTo).orElse(null);
                            Float min = Arrays.stream(fvals).min(Float::compareTo).orElse(null);
                            // 将在面内的点的计入面雨量求值
                            double areaRain = DmgisUtils.getAreaRainWgs(min, max, fs, points, point3Ds);
                            // 计算完毕返回对象
                            list.add(new Mylfx(countyPoint.getName(), areaRain, countyPoint.getLon(), countyPoint.getLat()));
                        } else {
                            log.warn("三角网插值，需要至少三个点。当前行政面为：" + countyPoint.getName() + "，符合条件的值有：" + fvals.length + "个");
                        }
                    }
                    return list;
                }
            }
        }
        return list;
    }


//<------------------------------------------------------------------------------------------------------------------------------------------------->

    @Override
    public List<Mylfx> forecastedSurfaceRainfall(String date, String time, short ntimes, short areatype) {
        // 获取区域雨量统计表数据
        List<AreaRain> areaRains = new ArrayList<>();
        List<Mylfx> list = new ArrayList<>();
        // 处理时间
        Timestamp dateTime = DateUtil.localDateTimeToTimestamp(DateUtil.stringToLocalDateTime(date + " " + "00:00:00"));
        Timestamp endTime = DateUtil.localDateTimeToTimestamp(DateUtil.stringToLocalDateTime(date + " " + "24:00:00"));

        int type = 1;
        areaRains = areaRainMapper.selectList(new LambdaQueryWrapper<AreaRain>()
                .between(AreaRain::getObservtime, dateTime, endTime)
                .eq(AreaRain::getType, type)
                .eq(AreaRain::getAreatype, areatype)
                .eq(AreaRain::getNtimes, ntimes));
        if (areaRains.size() > 0) {
            for (AreaRain areaRain : areaRains) {
                // 判断为流域还是行政区(0流域，1行政)
                if (areaRain.getAreatype() == 0) {
                    // 根据流域名获取经纬度
                    RainWaterShed rainWaterShed = rainWaterShedMapper.selectOne(new LambdaQueryWrapper<RainWaterShed>()
                            .select(RainWaterShed::getName, RainWaterShed::getCenterpointx, RainWaterShed::getCenterpointy)
                            .eq(RainWaterShed::getName, areaRain.getAreaname()));
                    if (rainWaterShed != null) {
                        list.add(new Mylfx(rainWaterShed.getName(), areaRain.getRain(), rainWaterShed.getCenterpointx(), rainWaterShed.getCenterpointy()));
                    } else {
                        log.warn("表RainWaterShed中没有查询到表AreaRain对应的信息！");
                    }
                } else {
                    CountyPoint countyPoint = countyPointMapper.selectOne(new LambdaQueryWrapper<CountyPoint>()
                            .select(CountyPoint::getName, CountyPoint::getLon, CountyPoint::getLat)
                            .eq(CountyPoint::getName, areaRain.getAreaname()));
                    if (countyPoint != null) {
                        list.add(new Mylfx(countyPoint.getName(), areaRain.getRain(), countyPoint.getLon(), countyPoint.getLat()));
                    } else {
                        log.warn("表CountyPoint中没有查询到表AreaRain对应的信息！");
                    }
                }
            }
            return list;
        }
        log.warn("区域雨量统计表无符合条件的数据！！！");
        log.warn("生成数据中...");

        List<TownshipForecast> townshipForecastList = new ArrayList<>();
        townshipForecastList = townshipForecastMapper.selectList(new LambdaQueryWrapper<TownshipForecast>()
                .select(TownshipForecast::getLongitude, TownshipForecast::getLatitude, TownshipForecast::getRain)
                .eq(TownshipForecast::getDatechar, dateTime)
                .eq(TownshipForecast::getTimechar, time)
                .eq(TownshipForecast::getNtimes, ntimes));

        townshipForecastList.removeIf(i -> i.getRain() < 0);

        if (townshipForecastList.size() > 0) {
            // 判断查询流域还是行政区
            if (areatype == 0) {
                // 获取玉林市的所有流域
                List<RainWaterShed> rainWaterSheds = rainWaterShedMapper.selectList(new LambdaQueryWrapper<RainWaterShed>()
                        .eq(RainWaterShed::getDrainagearea, "玉林"));
                // 处理流域的点集（每组坐标用“；”隔开  一组坐标以“，”隔开）
                for (RainWaterShed waterShed : rainWaterSheds) {
                    // 流域的面的点集
                    List<DmMapPoint> points = new ArrayList<>();
                    String[] split = waterShed.getCoordinate().split(";");
                    for (int i = 0; i < split.length; i++) {
                        String[] split1 = split[i].split(",");
                        points.add(new DmMapPoint(Double.valueOf(split1[0]), Double.valueOf(split1[1])));
                    }

                    // 判断点在面内并准备好getAreaRain()方法所需要的参数
                    List<Float> floatList = new ArrayList<>();
                    List<Point3D> point3Ds = new ArrayList<>();
                    for (TownshipForecast townshipForecast : townshipForecastList) {
                        boolean b = MapCommon.pointWithinPolygon(points, townshipForecast.getLongitude(), townshipForecast.getLatitude());
                        if (b) {
                            floatList.add(Float.valueOf(townshipForecast.getRain().toString()));
                            point3Ds.add(new Point3D(townshipForecast.getLongitude(), townshipForecast.getLatitude(), townshipForecast.getRain()));
                        }
                    }
                    // 将集合转化为数组
                    Float[] fvals = floatList.toArray(new Float[floatList.size()]);

                    float[] fs = new float[fvals.length];
                    for (int i = 0; i < fvals.length; i++) {
                        fs[i] = fvals[i];
                    }

                    // 三角网插值，需要至少三个点
                    if (fvals.length > 3) {
                        // 计算最大最小值
                        Float max = Arrays.stream(fvals).max(Float::compareTo).orElse(null);
                        Float min = Arrays.stream(fvals).min(Float::compareTo).orElse(null);
                        // 将在面内的点的计入面雨量求值
                        double areaRain = DmgisUtils.getAreaRainWgs(min, max, fs, points, point3Ds);
                        // 计算完毕返回对象
                        list.add(new Mylfx(waterShed.getName(), areaRain, waterShed.getCenterpointx(), waterShed.getCenterpointy()));
                    } else {
                        log.warn("三角网插值，需要至少三个点。当前流域为：" + waterShed.getName() + "，符合条件的值有：" + fvals.length + "个");
                    }
                }
                return list;
                // 处理为行政区的情况
            } else {
                // 获取玉林市的所有行政区:在表county_point里有行政区的信息，目前这里的所有数据都是玉林的，如果后期有其他区域的可以添加一个过滤条件
                List<CountyPoint> countyPoints = countyPointMapper.selectList(new LambdaQueryWrapper<CountyPoint>()
                        .select(CountyPoint::getName, CountyPoint::getLon, CountyPoint::getLat, CountyPoint::getRange));

                // 处理行政区的点集（每组坐标用“；”隔开  一组坐标以“，”隔开）
                for (CountyPoint countyPoint : countyPoints) {
                    // 行政区的面的点集
                    List<DmMapPoint> points = new ArrayList<>();
                    String[] split = countyPoint.getRange().split(";");
                    for (int i = 0; i < split.length; i++) {
                        String[] split1 = split[i].split(",");
                        points.add(new DmMapPoint(Double.valueOf(split1[0]), Double.valueOf(split1[1])));
                    }
                    // 判断点在面内并准备好getAreaRain()方法所需要的参数
                    List<Float> floatList = new ArrayList<>();
                    List<Point3D> point3Ds = new ArrayList<>();
                    for (TownshipForecast townshipForecast : townshipForecastList) {
                        boolean b = MapCommon.pointWithinPolygon(points, townshipForecast.getLongitude(), townshipForecast.getLatitude());
                        if (b) {
                            floatList.add(Float.valueOf(townshipForecast.getRain().toString()));
                            point3Ds.add(new Point3D(townshipForecast.getLongitude(), townshipForecast.getLatitude(), townshipForecast.getRain()));
                        }
                    }
                    // 将集合转化为数组
                    Float[] fvals = floatList.toArray(new Float[floatList.size()]);

                    float[] fs = new float[fvals.length];
                    for (int i = 0; i < fvals.length; i++) {
                        fs[i] = fvals[i];
                    }

                    // 三角网插值，需要至少三个点
                    if (fvals.length > 3) {
                        // 计算最大最小值
                        Float max = Arrays.stream(fvals).max(Float::compareTo).orElse(null);
                        Float min = Arrays.stream(fvals).min(Float::compareTo).orElse(null);
                        // 将在面内的点的计入面雨量求值
                        double areaRain = DmgisUtils.getAreaRainWgs(min, max, fs, points, point3Ds);
                        // 计算完毕返回对象
                        list.add(new Mylfx(countyPoint.getName(), areaRain, countyPoint.getLon(), countyPoint.getLat()));
                    } else {
                        log.warn("三角网插值，需要至少三个点。当前行政面为：" + countyPoint.getName() + "，符合条件的值有：" + fvals.length + "个");

                    }
                }
                return list;
            }
        }
        return list;
    }
}
